package com.bblocks.util;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * Kryo 序列化方案
 * 优势：数据小、序列化（正负）快
 * 缺陷：redis中数据不可见、bean字段变更可能会出错
 * 使用：
 * KryoRedisSerializer<Object> kryoSerializer = new KryoRedisSerializer<>(Object.class);
 * @param <T>
 */
@Slf4j
//@Component
public class KryoRedisSerializer<T> implements RedisSerializer<T> {
    public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];


    private Class<T> clazz;
    public KryoRedisSerializer(Class<T> clazz) {
        super();
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (t == null) {
            return EMPTY_BYTE_ARRAY;
        }
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();){
			KryoSerializer.getInstance().serialize(t,baos);
			return baos.toByteArray();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new SerializationException("serialize error");
        }
    }

	public int serialize(T t, ByteArrayOutputStream baos) throws SerializationException, IOException {
		if (t == null) {
			baos.write(EMPTY_BYTE_ARRAY);
			return 1;
		}
		try  {
			KryoSerializer.getInstance().serialize(t,baos);
			return baos.size();
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new SerializationException("serialize error");
		}
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        try {
            return (T) KryoSerializer.getInstance().deserialize(bytes);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new SerializationException("deserialize error");//无效数据，建议删除
        }
    }
}